import socket
import os
import subprocess
import ModuleOne
import ModuleTwo
import ModuleThree
import re
import time

"服务端程序入口"

# 读取配置文件中的端口信息
def read_config():
    readfile = open('config.ini','r')
    rs = readfile.readlines()
    for s in rs:
        s1 = s.replace('\n','')
        if s1.startswith('port'):
            port = s1.split('=')[1]
            return int(port)

# 判断是否启用了白名单功能，并读取白名单的ip
def read_config_ipwhite():
    readfile = open('config.ini','r')
    rs = readfile.readlines()

    # 如果存在白名单配置，则返回ip列表，否则输出异常，返回none
    try:
        for s in rs:
            s1 = s.replace('\n','')
            if s1.startswith('ipwhite'):
                iplists = s1.split('=')[1].split(';')
        return iplists
    except:
        return 'none'

# 建立socket会话，收发数据
def tcp_socket_connect(port, new_socket):
    rec_data = new_socket.recv(1024)
    # 根据客户端发送过来的指定，执行相应操作
    if rec_data.decode('utf-8') == '1':
        # 1. 调用功能模块ModuleOne.
        print('接收到客户端功能请求1,服务端将执行下载任务')
        try:
            new_socket.send('服务端应答：接受到指令1'.encode('gbk'))
            url = new_socket.recv(1024).decode('utf-8')
            savepath = new_socket.recv(1024).decode('utf-8')

            ModuleOne.ModuleOne(url,savepath)
            new_socket.send('服务端应答：success'.encode('gbk'))
            new_socket.close()
            print('\n---------------------------')
        except:
            new_socket.send('服务端应答:fail'.encode('gbk'))
            new_socket.close()
            print('\n---------------------------')
    
    elif rec_data.decode('utf-8') == '2':
        # 2. 调用功能模块ModuleTwo.py
        print('接收到客户端功能请求2，服务端将执行解压任务')
        new_socket.send('服务端应答: 接收到指令2'.encode('gbk'))

        #接受客户端发送过来的zip文件路径和解压后的路径
        try:
            rec_zipfilepath = new_socket.recv(1024).decode('utf-8')
            print(rec_zipfilepath)
            rec_unzipfilepath = new_socket.recv(1024).decode('utf-8')
            print(rec_unzipfilepath)
            ModuleTwo.ModuleTwo(rec_zipfilepath , rec_unzipfilepath)
            new_socket.send('服务端应答：success'.encode('gbk'))
            new_socket.close()
            print('---------------------------')
        except:
            new_socket.send('服务端应答:参数传递有误或文件不存在，请检查'.encode('gbk'))
            new_socket.close()
            print('---------------------------')

    elif rec_data.decode('utf-8') == '3':
        # 3. 调用功能模块ModuleThree.py
        print('客户端功能请求3，服务端准备执行接收文件')
        new_socket.send('服务端应答：接收到指令3'.encode('gbk'))

        #接受客户端发送过来的文件名和保存路径
        try:
            rec_filename = new_socket.recv(1024).decode('utf-8')
            print(rec_filename)
            time.sleep(0.1)
            rec_savepath = new_socket.recv(1024).decode('utf-8')
            print(rec_savepath)
            time.sleep(0.1)
            print('------content-------')
            rec_content = new_socket.recv(1024*1024*1024).decode('utf-8')
            print(rec_content)
            ModuleThree.ModuleThree(rec_filename,rec_savepath,rec_content)
            
            new_socket.send('服务端应答：success'.encode('gbk'))
            new_socket.close()
            print('---------------------------')
        except:
            new_socket.send('服务端应答: 参数传递有误或文件不存在，请检查'.encode('gbk'))
            new_socket.close()
            print('---------------------------')

    elif rec_data.decode('utf-8') == '4':
        # 4. 不需要调用功能模块
        print('客户端功能请求4,准备执行cmd命令')
        new_socket.send('服务端应答：接收到指令4'.encode('gbk'))

        rec_command = new_socket.recv(1024).decode('utf-8')
        content = os.popen(rec_command).read()

        new_socket.send(content.encode('gbk'))
        new_socket.close()
        print('---------------------------')
    
    elif rec_data.decode('utf-8') == '5':
        # 5. 不需要调用功能模块
        print('客户端请求5，准备执行命令')
        new_socket.send('服务端应答：接收到指令5'.encode('gbk'))

        #接受客户端传过来的批处理或exe文件的路径
        rec_command_path = new_socket.recv(1024).decode('utf-8')

        #判断文件是否存在,并且文件是bat或exe结尾
        if os.path.exists(rec_command_path) and (rec_command_path.endswith('.bat') or rec_command_path.endswith('.exe')):
            print('需要执行的文件%s:'%rec_command_path)
            try:
                subprocess.Popen(rec_command_path)
                new_socket.send('服务端应答:success'.encode('gbk'))
                new_socket.close()
                print('---------------------------')
            except:
                print('执行失败，操作异常')
                new_socket.send('服务端应答: 执行失败，操作异常'.encode('gbk'))
                print('---------------------------')
        else:
            new_socket.send('服务端应答: 文件不存在或文件不是bat文件也不是exe文件'.encode('gbk'))
            print('---------------------------')
            new_socket.close()
    else: 
        print('输入的选择没有匹配到需要执行的动作,会话将关闭！！！')
        new_socket.send('输入的选择没有匹配到需要执行的动作,会话将关闭！！！'.encode('utf-8'))
        new_socket.close()
        print('---------------------------')

# 整个程序的入口     
if __name__ == '__main__':
    port = read_config()
    
    # 1. 创建一个socket，单线程，一次只允许一个客户端连接
    tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    ip_port = ('',port)
    tcp_socket.bind(ip_port)
    tcp_socket.listen(128)
    print('服务已经启动，业务端口为%s'%port)
    
    # 2. 等待客户端连接
    while True:
        newsocket,client_ip = tcp_socket.accept()
        try:
            # 检查是否启用白名单功能
            if read_config_ipwhite() == 'none':
                print('ip白名单功能没有启用!!!')
                tcp_socket_connect(port,newsocket)
            else:
                print('白名单功能启用,开始检查用户ip是否在白名单中')
                if client_ip[0] in read_config_ipwhite():
                    print('客户端ip地址在白名单里面，放行%s'%client_ip[0])
                    tcp_socket_connect(port,newsocket)
                else:
                    print('客户端ip地址不在白名单里面，拒绝连接%s'%client_ip[0])
                    print('-----------------------------------')
                    newsocket.close()

                    # 防止恶意程序疯狂连接，连接失败后，拒绝30秒
                    time.sleep(30)
                    continue
        except:
            print('有可能是客户端异常退出了，服务端将执行断言操作，重新监听！！')
            print('------------等待客户端连接-------------------------')

                
